package com.zn.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zn.entity.*;
import com.zn.mapper.OptionTradingContractMapper;
import com.zn.mapper.OptionTradingGoodsMapper;
import com.zn.service.MdInfoService;
import com.zn.util.Constant;
import com.zn.util.DateUtils;
import com.zn.util.UUIDUtils;
import com.zn.vo.*;
import com.zn.web.rpc.MdRemoteCall;
import com.zn.web.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;

/**
 * Created by yinjiawei on 2018/7/14.
 */
@Service
public class MdInfoServiceImpl implements MdInfoService {
    private static final Logger LOGGER = LoggerFactory.getLogger(MdInfoServiceImpl.class);
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private OptionTradingGoodsMapper optionTradingGoodsMapper;
    @Autowired
    private OptionTradingContractMapper optionTradingContractMapper;

    @Autowired
    private MdRemoteCall mdRemoteCall;

    @Override
    public OptionTradingGoods selectBytradingGoodsCode(String tradingGoodsCode){
        return optionTradingGoodsMapper.selectBytradingGoodsCode(tradingGoodsCode);
    }

    @Override
    public List<OptionTradingGoods> findtradingGoodsCodeAll(){
        return optionTradingGoodsMapper.findAll();
    }

    @Override
    public List<OptionTradingContract> selectIsTrading(){
        return optionTradingContractMapper.selectIsTrading();
    }


    @Override
    public void saveTgAndInstrumentMonth(String targetCode, Set<String> instrumentMonths) {
        OptionTradingGoods optionTradingGoods=optionTradingGoodsMapper.selectBytradingGoodsCode(targetCode);
        if (optionTradingGoods ==null){
            Object etfObj=redisTemplate.opsForHash().get(Constant.TARGET_CODE_LIST, targetCode);
            EtfMdInfo etfMdInfo=JSONObject.parseObject(etfObj.toString(),EtfMdInfo.class);
            optionTradingGoods=new OptionTradingGoods();
            optionTradingGoods.setTradingGoodsId(UUIDUtils.getUuid());
            optionTradingGoods.setTradingGoodsCode(targetCode);
            optionTradingGoods.setTradingGoodsName(etfMdInfo.getEtfName());
            optionTradingGoodsMapper.insertSelective(optionTradingGoods);
        }else{
            /**将所有的合约月份设置成 不可交易**/
            optionTradingContractMapper.setIsTradingDisabled();
            for(String instrumentMonth:instrumentMonths){
                OptionTradingContract optionTradingContract=optionTradingContractMapper.selectByGoodsIdAndMonth(optionTradingGoods.getTradingGoodsId(), instrumentMonth);
                if(optionTradingContract!=null){
                    //如果存在 则将合约月份设置成可交易
                    optionTradingContract.setIsTrading(0);
                    optionTradingContractMapper.updateByPrimaryKeySelective(optionTradingContract);
                }else{
                    //如果不存在则新增
                    optionTradingContract=new OptionTradingContract();
                    OptionTradingContract optionTradingContractLast=optionTradingContractMapper.selectLastByGoodsId(optionTradingGoods.getTradingGoodsId());
                    if(optionTradingContractLast!=null){
                        optionTradingContract.setOpenFee(optionTradingContractLast.getOpenFee() == null ? new BigDecimal(0): optionTradingContractLast.getOpenFee());
                        optionTradingContract.setCloseFee(optionTradingContractLast.getCloseFee()== null ? new BigDecimal(0):optionTradingContractLast.getCloseFee());
                        optionTradingContract.setCostOpenFee(optionTradingContractLast.getCostOpenFee()== null ? new BigDecimal(0):optionTradingContractLast.getCostOpenFee());
                        optionTradingContract.setCostCloseFee(optionTradingContractLast.getCostCloseFee()== null ? new BigDecimal(0):optionTradingContractLast.getCostCloseFee());
                    }else{
                        optionTradingContract.setOpenFee(new BigDecimal(0));
                        optionTradingContract.setCloseFee(new BigDecimal(0));
                        optionTradingContract.setCostOpenFee(new BigDecimal(0));
                        optionTradingContract.setCostCloseFee(new BigDecimal(0));
                    }
                    optionTradingContract.setContractGoodsId(UUIDUtils.getUuid());
                    optionTradingContract.setTradingGoodsId(optionTradingGoods.getTradingGoodsId());
                    optionTradingContract.setContractMonthName(instrumentMonth);
                    optionTradingContract.setIsTrading(0);
                    optionTradingContract.setCreateTime(new Date());
                    optionTradingContract.setUpdateTime(new Date());
                    optionTradingContractMapper.insertSelective(optionTradingContract);
                }
            }
        }

    }

    /**
     * 首页获取所有标的信息和日期
     *
     * @return
     *  targetList   所有标的信息
     *  targetDateList  当前标的交易日期
     *  execList   当前标的首个交易日期行权价格
     *  manyHyMdInfoList   认购合约
     *  emptyHyMdInfoList  认沽合约
     */
    @Override
    public Map<String, List<?>> getTargetList(){

        //初始化
        Map<String, List<?>> targetMap = new HashMap<String, List<?>>();

        //获取所有标的信息
        Map<Object, Object> mapTarget = redisTemplate.opsForHash().entries(Constant.TARGET_CODE_LIST);

        //判断是否存在标的信息
        if (mapTarget.size() > 0){

            List<EtfMdInfo> etfMdInfoList = new LinkedList<EtfMdInfo>();
            List<TradingGoodsVo> targetList = new LinkedList<TradingGoodsVo>();
            List<TradingDateVo> targetDateList = new LinkedList<TradingDateVo>();
            int i = 0;

            for (Object key : mapTarget.keySet()){

                EtfMdInfo etfMdInfo = JSONObject.parseObject(mapTarget.get(key).toString(), EtfMdInfo.class);
                TradingGoodsVo target = new TradingGoodsVo();
                target.setTradingGoodsName(etfMdInfo.getEtfName());
                target.setTradingGoodsCode(key.toString());
                targetList.add(target);

                if ( i == 0) {
                    //获取标的最新价
                    etfMdInfoList.add(etfMdInfo);
                    i++;
                }
            }

            //获取默认第一个标的最新交易日期
            String key = checkRedisKey(Constant.INSTRUMENT_MONTH_SET+targetList.get(0).getTradingGoodsCode());
            Set<String> targetDateSet = redisTemplate.opsForSet().members(key);
            for (String ym: targetDateSet){
                TradingDateVo hyDate = new TradingDateVo();
                hyDate.setContractMonth(ym);
                targetDateList.add(hyDate);
            }

            //按交易日期升序
            Collections.sort(targetDateList, new Comparator<TradingDateVo>() {
                @Override
                public int compare(TradingDateVo o1, TradingDateVo o2) {
                    return o1.getContractMonth().compareTo(o2.getContractMonth());
                }
            });
            targetMap.put("target", targetList);
            targetMap.put("hyDate", targetDateList);
            targetMap.put("etfMdInfo", etfMdInfoList);
        }
        return targetMap;
    }

    /**
     * 根据标的与交易日期获取最新价
     * @param record  标的序号
     * @param record  交易日期
     * @return
     */
    @Override
    public Map<String, List<?>> findTargetList (TradingVo record){

        //初始化
        Map<String, List<?>> targetMap = new HashMap<String, List<?>>();
        List<TradingDateVo> targetDateList = new LinkedList<TradingDateVo>();
        List<OptionSymbol> statInfoList = new LinkedList<OptionSymbol>();
        List<EtfMdInfo> etfMdInfoList = new LinkedList<EtfMdInfo>();
        List<StrikePriceGoodsVo> execList = new LinkedList<StrikePriceGoodsVo>();

        //判断是否传递标的信息
        if (StringUtils.isBlank(record.getTradingGoodsCode())){
            return targetMap;
        }

        //判断是否传递标的交易日期
        if (StringUtils.isBlank(record.getInstrumentMonth())){
            //根据标的获取交易日期
            String key = checkRedisKey(Constant.INSTRUMENT_MONTH_SET+record.getTradingGoodsCode());
            Set<String> targetDateSet = redisTemplate.opsForSet().members(key);
            for (String ym : targetDateSet){
                TradingDateVo tradingDateVo = new TradingDateVo();
                tradingDateVo.setContractMonth(ym);
                targetDateList.add(tradingDateVo);
            }
            record.setInstrumentMonth(targetDateList.get(0).getContractMonth());

            //获取标的最新价
            String OEtfMdInfo = redisTemplate.opsForHash().get(Constant.TARGET_CODE_LIST, record.getTradingGoodsCode()).toString();
            EtfMdInfo etfMdInfo = JSONObject.parseObject(OEtfMdInfo, EtfMdInfo.class);
            etfMdInfoList.add(etfMdInfo);
        }

        //获取标的默认第一个日期最新行权价
        String key = checkRedisKey(Constant.EXECS_PRICE_SET+record.getTradingGoodsCode()+":"+record.getInstrumentMonth());
        Set<String> targetExecSet = redisTemplate.opsForSet().members(key);
        for (String targetExec : targetExecSet){
            StrikePriceGoodsVo exec = new StrikePriceGoodsVo();
            exec.setStrikePrice(targetExec);
            execList.add(exec);
        }

        //获取标的默认第一个日期最新合约价
        key = checkRedisKey(Constant.OPTION_SYMBOL_INFO);
        List<Object> reslutMapList = redisTemplate.opsForHash().values(key);
        for (Object obj : reslutMapList){
            statInfoList.add(JSONObject.parseObject(obj.toString(), OptionSymbol.class));
        }

        key = checkRedisKey(Constant.OPTION_TICKL_INFO+record.getTradingGoodsCode()+":"+record.getInstrumentMonth());
        Map<Object, Object> map = redisTemplate.opsForHash().entries(key);

        //排序获取最新行权价和对应认购认沽信息
        targetMap = this.mateNewTarget(execList, map);

        //请求新标的返回交易日期
        if (targetDateList.size() > 0){
            //按交易日期升序
            Collections.sort(targetDateList, new Comparator<TradingDateVo>() {
                @Override
                public int compare(TradingDateVo o1, TradingDateVo o2) {
                    return o1.getContractMonth().compareTo(o2.getContractMonth());
                }
            });
            targetMap.put("hyDate", targetDateList);
            targetMap.put("etfMdInfo", etfMdInfoList);
        }

        if (!"".equals(record.getType()) && record.getType() != null) {
            //其它获取所有
            switch (record.getType()) {
                case "1"://获取认购
                    targetMap.remove("sellHy");
                    break;
                case "2"://获取认沽
                    targetMap.remove("buyHy");
                    break;
            }
        }
        return targetMap;
    }

    /**
     * 通过排序行权价匹配最新认购、认沽信息
     *
     * @param execList      标的最新行权价
     * @param map          当天合约信息
     * @return
     *      execList    最新行权价
     *      manyHyMdInfoList    认购合约
     *      emptyHyMdInfoList    认沽合约
     */

    public Map<String, List<?>> mateNewTarget(List<StrikePriceGoodsVo> execList, Map<Object, Object> map){

        //初始化
        Map<String, List<?>> targetMap = new HashMap<String, List<?>>();
        List<OptionMarketDataField> buyOptionMarketDataList = new LinkedList<OptionMarketDataField>();
        List<OptionMarketDataField> sellOptionMarketDataList = new LinkedList<OptionMarketDataField>();
        List<OptionMarketDataField> OptionMarketDataList = new LinkedList<OptionMarketDataField>();

        //按行权价升序
        Collections.sort(execList, new Comparator<StrikePriceGoodsVo>() {
            @Override
            public int compare(StrikePriceGoodsVo o1, StrikePriceGoodsVo o2) {
                return o1.getStrikePrice().compareTo(o2.getStrikePrice());
            }
        });

        for (Object key : map.keySet()){
            OptionMarketDataList.add(JSONObject.parseObject(map.get(key).toString(), OptionMarketDataField.class));
        }

        for (StrikePriceGoodsVo exec : execList){
            int a = 0;
            for (int i = 0; i < OptionMarketDataList.size(); i++){
                //对比行权价
                if (exec.getStrikePrice().equals(OptionMarketDataList.get(i).getExecsPrice())){
                    a++;
                    //判断区分认购和认沽信息
                    switch (OptionMarketDataList.get(i).getInstrumentType()){
                        case "1":
                            buyOptionMarketDataList.add(OptionMarketDataList.get(i));
                            OptionMarketDataList.remove(i);
                            i--;
                            break;
                        case "2":
                            sellOptionMarketDataList.add(OptionMarketDataList.get(i));
                            OptionMarketDataList.remove(i);
                            i--;
                            break;
                    }
                }

                //已获取到全部合约信息
                if (a == 2){
                    break;
                }

                //确实部分合约信息，传入空值
                if (i+1 == OptionMarketDataList.size()){
                    OptionMarketDataField optionMarketDataField = new OptionMarketDataField();
                    if (buyOptionMarketDataList.size() > sellOptionMarketDataList.size()){//少认沽传入空
                        sellOptionMarketDataList.add(optionMarketDataField);
                    }else if (sellOptionMarketDataList.size() > buyOptionMarketDataList.size()) {//少认购传入空
                        buyOptionMarketDataList.add(optionMarketDataField);
                    }else {//缺少对应两条合约数据
                        sellOptionMarketDataList.add(optionMarketDataField);
                        buyOptionMarketDataList.add(optionMarketDataField);
                    }
                }
            }
        }

        targetMap.put("exec", execList);
        targetMap.put("buyHy",buyOptionMarketDataList);
        targetMap.put("sellHy",sellOptionMarketDataList);

        return targetMap;
    }


    /**
     * 获取合约最新详情价
     * @param record
     * @return
     */
    @Override
    public OptionMarketDataField getTargetContract(TradingVo record){
        //获取合约最新信息
        String key = checkRedisKey(Constant.OPTION_TICKL_INFO+record.getTradingGoodsCode()+":"+record.getInstrumentMonth());
        Object reslut = redisTemplate.opsForHash().get(key, record.getInstrumentCode());
        OptionMarketDataField optionMarketDataField = JSONObject.parseObject(reslut.toString(), OptionMarketDataField.class);

        return optionMarketDataField;
    }

    /**
     * 获取新浪分时线数据（初）
     * @param record
     * @return
     */
    @Override
    public Object getSinaMinLine(TradingVo record){
        switch (record.getType()) {
            case "0":
                String sinaMinLine = mdRemoteCall.getSinaOptionMinLine(record.getInstrumentCode());
                JSONObject jsonObject = JSON.parseObject(JSON.parseObject(sinaMinLine).get("result").toString());
                JSONArray jsonArray = JSON.parseArray(jsonObject.get("data").toString());
                if (jsonArray.size() == 0){
                    String sinaFiveDayLine = mdRemoteCall.getSinaOptionFiveDayLine(record.getInstrumentCode());
                    jsonObject = JSON.parseObject(JSON.parseObject(sinaFiveDayLine).get("result").toString());
                    jsonArray = JSON.parseArray(jsonObject.get("data").toString());
                    jsonArray = jsonArray.getJSONArray(jsonArray.size()-1);
                }
                JSONArray jsonArrayS = new JSONArray();
                try {
                    String nowDateStr=DateUtils.convertDateToString(new Date());
                    Date beginTime= DateUtils.convertStringToDate("yyyy-MM-dd HH:mm", nowDateStr + " 11:30");
                    Date endTime=DateUtils.convertStringToDate("yyyy-MM-dd HH:mm", nowDateStr +" 13:00");
                    int a = 0;
                    for (int i = 0; i < jsonArray.size(); i++){//去除新浪中无效数据
                        JSONObject jsonObjets = JSON.parseObject(jsonArray.get(i).toString());
                        Date nowDate= DateUtils.convertStringToDate("yyyy-MM-dd HH:mm", nowDateStr + " " + jsonObjets.get("i"));
                        if(!DateUtils.belongCalendar(nowDate, beginTime, endTime)) {
                            jsonArrayS.add(a, jsonArray.get(i));
                            a++;
                        }
                    }
                }catch (Exception ex){
                    ex.getMessage();
                }
                return jsonArrayS;
            case "1":
                String sinaDayLine = mdRemoteCall.getSinaOptionDayLine(record.getInstrumentCode());
                JSONObject json = JSON.parseObject(JSON.parseObject(sinaDayLine).get("result").toString());
                return json.get("data");
            case "2":
                return mdRemoteCall.getEastmoneyMonthLine(record.getInstrumentCode());
        }
        return null;
    }

    /**
     * 获取所有合约信息
     * @return
     */
    @Override
    public List<OptionSymbol> getContractList(){
        List<OptionSymbol> optionSymbolList = new LinkedList<OptionSymbol>();
        String key = checkRedisKey(Constant.OPTION_SYMBOL_INFO.substring(0, Constant.OPTION_SYMBOL_INFO.length()-1));
        Map<Object, Object> target = redisTemplate.opsForHash().entries(key);
        if (target.size() > 0) {
            for (Object mapKey : target.keySet()) {
                optionSymbolList.add(JSONObject.parseObject(target.get(mapKey).toString(), OptionSymbol.class));
            }
        }
        return optionSymbolList;
    }

    /**
     * 判断key是否存在，获取最新key
     * @param key
     * @return
     */
    @Override
    public String checkRedisKey(String key){
        try {
            Date date = new Date();
            for (int i = 0; i <= 20; i++) {
                String keyDate = DateUtils.convertDateToString(DateUtils.addDay(date, -i));
                if (":".equals(key.substring(key.length() - 1, key.length()))){
                    keyDate = key + keyDate;
                }else {
                    keyDate = key + ":" + keyDate;
                }
                if (redisTemplate.hasKey(keyDate)) {
                    return keyDate;
                }
            }
            return null;
        }catch (Exception ex){
            LOGGER.error(ex.getMessage());
            return null;
        }
    }

    /**
     * 校验当前时间是否在交易时间段内
     * @param tradingTime
     * @return
     */
    @Override
    public boolean checkTradingTime(String tradingTime, Response response){
        boolean flag=false;
        try {
            /**dayType 工作日对应结果为 0, 休息日对应结果为 1, 节假日对应的结果为 2**/
            if (response.isSuccess() && response.getDayType()!=0){
                return flag;
            }

            //如果是工作日 则直接校验时间段
            if(response.isSuccess() && response.getDayType()==0){
                String [] tradingTimes=tradingTime.split("\\|");
                for(String time:tradingTimes){
                    String [] timeSlot = time.split("-");
                    String nowDateStr=DateUtils.convertDateToString(new Date());
                    Date beginTime= DateUtils.convertStringToDate("yyyy-MM-dd HH:mm", nowDateStr + " " + timeSlot[0]);
                    Date endTime=DateUtils.convertStringToDate("yyyy-MM-dd HH:mm",nowDateStr+" "+timeSlot[1]);
                    if(DateUtils.belongCalendar(new Date(), beginTime, endTime)){
                        flag = true;
                    }
                }
            }
            return flag;
        } catch (ParseException e) {
            e.printStackTrace();
            return false;
        }
    }

}
